package cn.edu.zjut.security;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint;
import org.springframework.web.cors.CorsUtils;

/**
 * @description:
 * @author:ZhouDan
 * @date: 2020/8/10
 * @version: 1.0
 */
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true, jsr250Enabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired(required = false)
    private MyAuthenticationSuccessHandler myAuthenticationSuccessHandler;
    @Autowired(required = false)
    private MyAuthenticationFailHandler myAuthenticationFailHandler;
    @Autowired(required = false)
    private MyLogoutSuccessHandler myLogoutSuccessHandler;

    @Override
    public void configure(WebSecurity web) throws Exception {
        web
                .ignoring()
                //
                .antMatchers("/resources/**");
    }

    protected void registerAuthentication(AuthenticationManagerBuilder auth) throws Exception {
        auth
                .inMemoryAuthentication()
                .withUser("userName")
                .password(new BCryptPasswordEncoder().encode("password"))
                .roles("USER")
                .and()
                .withUser("admin")
                .password("password")
                .roles("ADMIN", "USER");
    }

    private static String REALM = "IO";

    @Override
    protected void configure(HttpSecurity http) throws Exception {

        http
                .csrf().disable()
                .formLogin()
                .loginPage("/login")
                .usernameParameter("userName").passwordParameter("password").permitAll()
                .loginProcessingUrl("/login")
                //　自定义的登录验证成功或失败后的去向
                .successHandler(myAuthenticationSuccessHandler).failureHandler(myAuthenticationFailHandler)
                .and()
                .authorizeRequests()
                .requestMatchers(CorsUtils::isPreFlightRequest).permitAll()
                .antMatchers("/login").permitAll()
                .anyRequest().authenticated()
                // 其他url路径之需要登陆即可.
                //.anyRequest().authenticated()
                .and()
                .logout()
                .logoutSuccessUrl("/user/logout").logoutSuccessHandler(myLogoutSuccessHandler)
                .permitAll()
        ;
    }
    // @formatter:on

    /**
     * 生成 BasicAuthenticationEntryPoint 对象, 在该对象的支持下, 通过验证的请求, 返回的response 将会自动加上
     * WWW-Authenticate Header.  在该对象的支持下, 未通过验证的请求, 返回的 response 为 UNAUTHORIZED 错误.
     *
     * @return
     */
    @Bean
    public BasicAuthenticationEntryPoint getBasicAuthenticationEntryPoint() {
        BasicAuthenticationEntryPoint entryPoint = new BasicAuthenticationEntryPoint();
        entryPoint.setRealmName(REALM);
        return entryPoint;
    }
    /**
     * 密码生成策略.
     *
     * @return
     */
    @SuppressWarnings("deprecation")
    @Bean
    public NoOpPasswordEncoder passwordEncoder() {
        BasicAuthenticationEntryPoint a;
        return (NoOpPasswordEncoder) NoOpPasswordEncoder.getInstance();
    }
}
